package org.example.learn.javassist.annotation;

import javassist.*;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.Bytecode;
import javassist.bytecode.ConstPool;
import javassist.bytecode.MethodInfo;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.LongMemberValue;
import javassist.bytecode.annotation.StringMemberValue;

import java.io.IOException;

/**
 * 生成类并添加注解
 */
public class GenerateClassAddAnnotation {

    public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException {
        ClassPool pool = ClassPool.getDefault();

        // 创建类
        CtClass ctClass = pool.makeClass("org.example.learn.javassist.annotation.TestF");

        // 创建方法
        CtMethod ctMethod = new CtMethod(CtClass.longType,"strToLong",new CtClass[]{pool.get(String.class.getName())},ctClass);
        ctMethod.setModifiers(Modifier.PUBLIC); // 设置权限

        MethodInfo methodInfo = ctMethod.getMethodInfo();

        ConstPool constPool = methodInfo.getConstPool();

        // 添加类注解
        AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(constPool,AnnotationsAttribute.visibleTag); // 设置注解标签
        // 添加注解信息
        Annotation classAnnotation = new Annotation(ClassAnnotation.class.getName(),constPool);
        classAnnotation.addMemberValue("ClassDeclare",new StringMemberValue("测试F",constPool));
        classAnnotation.addMemberValue("alias",new StringMemberValue("testF",constPool));
        classAnnotation.addMemberValue("timeout", new LongMemberValue(50L,constPool));
        annotationsAttribute.setAnnotation(classAnnotation);
        ctClass.getClassFile().addAttribute(annotationsAttribute);


        // 添加方法注解
        AnnotationsAttribute methodA = new AnnotationsAttribute(constPool,AnnotationsAttribute.visibleTag);
        Annotation methodAn = new Annotation("org/example/learn/javassist/annotation/MethodAnnotation",constPool);
        methodAn.addMemberValue("name",new StringMemberValue("toLong",constPool));
        methodAn.addMemberValue("api",new StringMemberValue("strToLong",constPool));
        methodAn.addMemberValue("type",new StringMemberValue("Get",constPool));

        methodA.setAnnotation(methodAn);

        methodInfo.addAttribute(methodA);

        // 指令
        Bytecode bytecode = new Bytecode(constPool);
        bytecode.addGetstatic("java/math/BigDecimal","TEN","Ljava/math/BigDecimal");
        bytecode.addInvokevirtual("java/math/BigDecimal","longValue","()D");
        bytecode.addReturn(CtClass.longType);

        methodInfo.setCodeAttribute(bytecode.toCodeAttribute());

        ctClass.addMethod(ctMethod);

        ctClass.writeFile();
    }
}
